package engine;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import utility.Vector3;


public class DeltaFormFactors {

	private int facesWide;
	private double faceWidth;
	
	public double[][] front;
	public double[][] side;
	
	
	private double total = 0;
	
    private static Vector3 point = new Vector3(new double[]{0, 0, 0});
    
	public DeltaFormFactors() {
		facesWide = Core.FACES_WIDE;
		front = new double[facesWide][facesWide];
		side = new double[facesWide][facesWide / 2];
		faceWidth = 2.0 / facesWide;
		calculateDeltaFormFactorsFront();
		calculateDeltaFormFactorsSide();
		render();
		normalize();
	}

	private void calculateDeltaFormFactorsFront() {
	    Vector3 center = new Vector3(new double[]{0, 0, 1});
	    double distFromPointToCenter = center.distance(point);
	    for(int x = 0; x < facesWide; x++) {
	        for(int y = 0; y < facesWide; y++) {
	            Vector3 pixel = new Vector3(new double[]{
	            		-1 + x * faceWidth + faceWidth / 2.0, 
	            		-1 + y * faceWidth + faceWidth / 2.0, 
	            		center.z()});
	            double distFromCenterToPixel = center.distance(pixel);
	            double distFromPointToPixel = point.distance(pixel);
	            double cos = Math.cos(Math.asin(distFromCenterToPixel / 
	                            distFromPointToPixel));
	            double lambert = (Math.pow(distFromPointToPixel,2) + 
	            		Math.pow(distFromPointToCenter, 2) - 
	            		Math.pow(distFromCenterToPixel, 2)) /
	            		(2 * distFromPointToPixel * 
	            				distFromPointToCenter);
	            double value = cos * lambert;
	            front[x][y] = value;
	            total += value;
	        }
	    }
	}

	private void calculateDeltaFormFactorsSide() {
        Vector3 sideCenter = new Vector3(new double[]{0, 1, 0});
        Vector3 frontCenter = new Vector3(new double[]{0, 0, 1});
        double distFromPointToFrontCenter = frontCenter.distance(point);
        for(int x = 0; x < facesWide; x++) {
            for(int z = 0; z < facesWide / 2; z++) {
                Vector3 pixel = new Vector3(new double[]{
                		-1 + x * faceWidth + faceWidth / 2.0, 1, 
                		z * faceWidth + faceWidth / 2.0});
                double distFromCenterToPixel = sideCenter.distance(pixel);
                double distFromPointToPixel = point.distance(pixel);
                double distFromFrontCenterToPixel = frontCenter.distance(pixel);
                double cos = Math.cos(Math.asin(distFromCenterToPixel / 
                        distFromPointToPixel));
                double lambert = (Math.pow(distFromPointToPixel,2) + 
                		Math.pow(distFromPointToFrontCenter, 2) - 
                		Math.pow(distFromFrontCenterToPixel, 2)) /
                		(2 * distFromPointToPixel * 
                				distFromPointToFrontCenter);
                double value = cos * lambert;
                side[x][z] = value;
                total += value * 4;
            }
        }
	}
	
	public void normalize() {
		for(int i = 0; i < front.length; i++) {
			for(int j = 0; j < front[i].length; j++) {
				front[i][j] = front[i][j] / total;
			}
		}
		for(int i = 0; i < side.length; i++) {
			for(int j = 0; j < side[i].length; j++) {
				side[i][j] = side[i][j] / total;
			}
		}
	}
	
	// Only used for visual testing
	private void render() {
		int width = 100;
		int height = 100;
		int size = width / facesWide;
		BufferedImage img = new BufferedImage(width, height, 
				BufferedImage.TYPE_BYTE_GRAY);
		WritableRaster writer = img.getRaster();
		
		for(int x = 0; x < 100; x++) {
			for(int y = 0; y < 100; y++) {
				double gray = front[(int) x / size][(int)y / size];
				gray *= 255;
				if (gray > 255) {
					gray = 255;
				}
				writer.setPixel(x, y, new int[]{(int)gray});
			}
		}
		try {
			ImageIO.write(img, "png", new File("frontEx.png"));
			System.out.println("Wrote to file frontEx.png.");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
